package com.hfb.mashibing.alip8.interview.deadlock;

/**
 * 问题描述：
 * 五个哲学家围着一张圆桌就餐，他们每个人面前都有一盘通心粉。由于通心粉很滑，所以需要两只筷子才能夹住，但每两个盘子之间只放着一只筷子。
 * 哲学家只有两个动作：要么就餐，要么思考。而且他们之间从不交谈。
 * 当一个哲学家饿了的时候，就拿起盘子左右两边的筷子开始就餐（不能同时拿起两只筷子）。就餐完以后，就把筷子放回盘子左右，继续思考。
 *
 * 注意：对java多线程不熟悉的可以先看下生产者－消费者模型是怎么实现的，然后再独立实现哲学家就餐问题．
 *
 * 解决方案１:
 *      哲学家要进餐时，要么同时拿起两支筷子，要么一支筷子都不拿
 */
public class PhilosopherQuestion1 {
    // chopsticks
    private boolean[] used = new boolean[] { false, false, false, false, false };
    private static String LOCK = "lock";

    public static void main(String[] args) {
        PhilosopherQuestion1 philosopherQuestion = new PhilosopherQuestion1();
        philosopherQuestion.new Philosopher(0).start();
        philosopherQuestion.new Philosopher(1).start();
        philosopherQuestion.new Philosopher(2).start();
        philosopherQuestion.new Philosopher(3).start();
        philosopherQuestion.new Philosopher(4).start();
    }

    class Philosopher extends Thread {
        private int num;

        public Philosopher(int num) {
            this.num = num;
        }

        public void eating() {
            System.out.println("my num is " + num + " , I am eating...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void thinking() {
            System.out.println("my num is " + num + ", I am thinking...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        //拿筷子时只要有一个筷子已经被占用，就要放弃拿筷子，并释放锁进入等待状态
        //得到通知后，再进入就绪状态，重新竞争锁
        public void takeChopsticks(){
            synchronized(LOCK) {
                if (used[num] || used[(num + 1) % 5]) {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //拿到两支筷子了
                used[num] = true;
                used[(num + 1) % 5] = true;
            }
        }

        //放下筷子时，也要申请锁，然后通知所有等待的线程
        public void putDownChopsticks() {
            synchronized(LOCK) {
                used[num] = false;
                used[(num + 1) % 5] = false;
                System.out.println("my num is " + num + " , I have finished...");
                LOCK.notifyAll();
            }
        }

        @Override
        public void run() {
            while(true) {
                thinking();
                takeChopsticks();
                eating();
                putDownChopsticks();
            }
        }
    }

}
